41a216cav5JJbtDQnusfuMa_1x_Xpw tools/libxutil/debug.h
40e9808eyjiahG5uF6AMelNVujBzCg tools/libxutil/enum.c
40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/libxutil/enum.h
+4284c2ecWyadIhHF1u_QSgWqIXkaLA tools/libxutil/fd_stream.c
+4284c2ecEOOcF6fZUf_NsZzYAoNo-w tools/libxutil/fd_stream.h
40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c
40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h
40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using fds.
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "allocate.h"
+#include "fd_stream.h"
+
+#define MODULE_NAME "fd_stream"
+#define DEBUG 1
+//#undef DEBUG
+#include "debug.h"
+
+static int fd_read(IOStream *s, void *buf, size_t n);
+static int fd_write(IOStream *s, const void *buf, size_t n);
+static int fd_error(IOStream *s);
+static int fd_close(IOStream *s);
+static void fd_free(IOStream *s);
+static int fd_flush(IOStream *s);
+
+/** Methods used by a fd IOStream. */
+static const IOMethods fd_methods = {
+ read: fd_read,
+ write: fd_write,
+ error: fd_error,
+ close: fd_close,
+ free: fd_free,
+ flush: fd_flush,
+};
+
+/** Get the fd data.
+ *
+ * @param io fd stream
+ * @return data
+ */
+static inline FDData * fd_data(IOStream *io){
+ return (FDData *)io->data;
+}
+
+/** Test if a stream is a fd stream.
+ *
+ * @param io stream
+ * @return 0 if a fd stream, -EINVAL if not
+ */
+int fd_stream_check(IOStream *io){
+ return (io && io->methods == &fd_methods ? 0 : -EINVAL);
+}
+
+/** Get the data for a fd stream.
+ *
+ * @param io stream
+ * @param data return value for the data
+ * @return 0 if a fd stream, -EINVAL if not
+ */
+int fd_stream_data(IOStream *io, FDData **data){
+ int err = fd_stream_check(io);
+ if(err){
+ *data = NULL;
+ } else {
+ *data = fd_data(io);
+ }
+ return err;
+}
+
+
+/** Write to the underlying fd.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int fd_write(IOStream *s, const void *buf, size_t n){
+ FDData *data = fd_data(s);
+ int k;
+ k = write(data->fd, buf, n);
+ return k;
+}
+
+/** Read from the underlying stream;
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int fd_read(IOStream *s, void *buf, size_t n){
+ FDData *data = fd_data(s);
+ int k;
+ k = read(data->fd, buf, n);
+ //printf("> fd_read> buf=%p n=%d --> k=%d\n", buf, n, k);
+ return k;
+}
+
+/** Flush the fd (no-op).
+ *
+ * @param s fd stream
+ * @return 0 on success, error code otherwise
+ */
+static int fd_flush(IOStream *s){
+ return 0;
+}
+
+/** Check if a fd stream has an error (no-op).
+ *
+ * @param s fd stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int fd_error(IOStream *s){
+ return 0;
+}
+
+/** Close a fd stream.
+ *
+ * @param s fd stream to close
+ * @return result of the close
+ */
+static int fd_close(IOStream *s){
+ FDData *data = fd_data(s);
+ return close(data->fd);
+}
+
+/** Free a fd stream.
+ *
+ * @param s fd stream
+ */
+static void fd_free(IOStream *s){
+ FDData *data = fd_data(s);
+ deallocate(data);
+}
+
+/** Create an IOStream for a fd.
+ *
+ * @param fd fd to wtap
+ * @return new IOStream using fd for i/o
+ */
+IOStream *fd_stream_new(int fd){
+ int err = -ENOMEM;
+ IOStream *io = NULL;
+ FDData *data = NULL;
+
+ io = ALLOCATE(IOStream);
+ if(!io) goto exit;
+ io->methods = &fd_methods;
+ data = ALLOCATE(FDData);
+ if(!data) goto exit;
+ io->data = data;
+ data->fd = fd;
+ err = 0;
+ exit:
+ if(err){
+ if(io){
+ if(data) deallocate(data);
+ deallocate(io);
+ io = NULL;
+ }
+ }
+ return io;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XMC_FD_STREAM_H_
+#define _XMC_FD_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+
+/** Data associated with a fd stream. */
+typedef struct FDData {
+ /** The socket file descriptor. */
+ int fd;
+} FDData;
+
+extern IOStream *fd_stream_new(int fd);
+extern int fd_stream_data(IOStream *io, FDData **data);
+extern int fd_stream_check(IOStream *io);
+
+#endif
+#endif /* !_XMC_FD_STREAM_H_ */
#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
/** Class of separator characters. */
-#define sep_class "{}()<>[]@!;"
+#define sep_class "{}()<>[]!;\"'"
#define comment_class "#"
#include <errno.h>
#endif
+#ifdef __KERNEL__
+#include <linux/random.h>
+
+int rand(void){
+ int v;
+ get_random_bytes(&v, sizeof(v));
+ return v;
+}
+
+#else
+#include <stdlib.h>
+#endif
+
#undef free
/** @file
static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
static int atom_equal(Sxpr x, Sxpr y);
static void atom_free(Sxpr obj);
+static Sxpr atom_copy(Sxpr obj);
static int string_print(IOStream *io, Sxpr obj, unsigned flags);
static int string_equal(Sxpr x, Sxpr y);
static void string_free(Sxpr obj);
+static Sxpr string_copy(Sxpr obj);
static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
static int cons_equal(Sxpr x, Sxpr y);
static void cons_free(Sxpr obj);
+static Sxpr cons_copy(Sxpr obj);
static int null_print(IOStream *io, Sxpr obj, unsigned flags);
static int none_print(IOStream *io, Sxpr obj, unsigned flags);
static int int_print(IOStream *io, Sxpr obj, unsigned flags);
static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
+static int err_print(IOStream *io, Sxpr obj, unsigned flags);
+static int nomem_print(IOStream *io, Sxpr obj, unsigned flags);
/** Type definitions. */
static SxprType types[1024] = {
- [T_NONE] { type: T_NONE, name: "none", print: none_print },
- [T_NULL] { type: T_NULL, name: "null", print: null_print },
- [T_UINT] { type: T_UINT, name: "int", print: int_print, },
- [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
- [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
- pointer: TRUE,
- free: atom_free,
- equal: atom_equal,
- },
- [T_STRING] { type: T_STRING, name: "string", print: string_print,
- pointer: TRUE,
- free: string_free,
- equal: string_equal,
- },
- [T_CONS] { type: T_CONS, name: "cons", print: cons_print,
- pointer: TRUE,
- free: cons_free,
- equal: cons_equal,
- },
+ [T_NONE] { .type= T_NONE, .name= "none", .print= none_print },
+ [T_NULL] { .type= T_NULL, .name= "null", .print= null_print },
+ [T_UINT] { .type= T_UINT, .name= "int", .print= int_print, },
+ [T_BOOL] { .type= T_BOOL, .name= "bool", .print= bool_print, },
+ [T_ERR] { .type= T_ERR, .name= "err", .print= err_print, },
+ [T_NOMEM] { .type= T_ERR, .name= "nomem", .print= nomem_print, },
+ [T_ATOM] { .type= T_ATOM, .name= "atom", .print= atom_print,
+ .pointer= TRUE,
+ .free= atom_free,
+ .equal= atom_equal,
+ .copy= atom_copy,
+ },
+ [T_STRING] { .type= T_STRING, .name= "string", .print= string_print,
+ .pointer= TRUE,
+ .free= string_free,
+ .equal= string_equal,
+ .copy= string_copy,
+ },
+ [T_CONS] { .type= T_CONS, .name= "cons", .print= cons_print,
+ .pointer= TRUE,
+ .free= cons_free,
+ .equal= cons_equal,
+ .copy= cons_copy,
+ },
};
/** Number of entries in the types array. */
int k = 0;
if(!io) return k;
if(flags & PRINT_TYPE){
- k += IOStream_print(io, "%s:", def->name);
+ k += IOStream_print(io, "%s:", def->name);
+ }
+ if(def->pointer && (flags & PRINT_ADDR)){
+ k += IOStream_print(io, "<%p>", get_ptr(x));
}
k += print_fn(io, x, flags);
return k;
}
+Sxpr objcopy(Sxpr x){
+ SxprType *def = get_sxpr_type(get_type(x));
+ ObjCopyFn *copy_fn = (def ? def->copy : NULL);
+ Sxpr v;
+ if(copy_fn){
+ v = copy_fn(x);
+ } else if(def->pointer){
+ v = ONOMEM;
+ } else {
+ v = x;
+ }
+ return v;
+}
+
/** General sxpr free function.
* Frees an sxpr using the free function for its type.
* Free functions must recursively free any subsxprs.
SxprType *def = get_sxpr_type(get_type(x));
if(def){
- if(def->free){
- def->free(x);
- } else if (def->pointer){
- hfree(x);
- }
+ if(def->free){
+ def->free(x);
+ } else if (def->pointer){
+ hfree(x);
+ }
}
}
*/
int cons_subset(Sxpr s, Sxpr t){
for( ; CONSP(t); t = CDR(t)){
- if(!CONSP(cons_member(s, CAR(t)))){
- return 0;
- }
+ if(!CONSP(cons_member(s, CAR(t)))){
+ return 0;
+ }
}
return 1;
}
#endif /* USE_GC */
/** Create a new atom with the given name.
+ * Makes an integer sxpr if the name can be parsed as an int.
*
* @param name the name
* @return new atom
*/
Sxpr atom_new(char *name){
Sxpr n, obj = ONOMEM;
+ long v;
- n = string_new(name);
- if(NOMEMP(n)) goto exit;
- obj = HALLOC(ObjAtom, T_ATOM);
- if(NOMEMP(obj)) goto exit;
- OBJ_ATOM(obj)->name = n;
+ if(convert_atol(name, &v) == 0){
+ obj = OINT(v);
+ } else {
+ n = string_new(name);
+ if(NOMEMP(n)) goto exit;
+ obj = HALLOC(ObjAtom, T_ATOM);
+ if(NOMEMP(obj)){
+ string_free(n);
+ goto exit;
+ }
+ OBJ_ATOM(obj)->name = n;
+ }
exit:
return obj;
}
hfree(obj);
}
+/** Copy an atom.
+ *
+ * @param obj to copy
+ */
+Sxpr atom_copy(Sxpr obj){
+ Sxpr v;
+ if(OBJ_ATOM(obj)->interned){
+ v = obj;
+ } else {
+ v = atom_new(atom_name(obj));
+ }
+ return v;
+}
+
/** Print an atom. Prints the atom name.
*
* @param io stream to print to
* @return number of bytes printed
*/
int atom_print(IOStream *io, Sxpr obj, unsigned flags){
- //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
- return string_print(io, OBJ_ATOM(obj)->name, flags);
+ return objprint(io, OBJ_ATOM(obj)->name, flags);
}
/** Atom equality.
return string_string(OBJ_ATOM(obj)->name);
}
+int atom_length(Sxpr obj){
+ return string_length(OBJ_ATOM(obj)->name);
+}
+
/** Get the C string from a string sxpr.
*
* @param obj string sxpr
* @return string
*/
char * string_string(Sxpr obj){
- return OBJ_STRING(obj);
+ return OBJ_STRING(obj)->data;
}
/** Get the length of a string.
* @return length
*/
int string_length(Sxpr obj){
- return strlen(OBJ_STRING(obj));
+ return OBJ_STRING(obj)->len;
}
/** Create a new string. The input string is copied,
*/
Sxpr string_new(char *s){
int n = (s ? strlen(s) : 0);
+ return string_new_n(s, n);
+}
+
+/** Create a new string. The input string is copied,
+ * and need not be null-terminated.
+ *
+ * @param s characters to put in the string (may be null)
+ * @param n string length
+ * @return new sxpr
+ */
+Sxpr string_new_n(char *s, int n){
Sxpr obj;
- obj = halloc(n+1, T_STRING);
+ obj = halloc(sizeof(ObjString) + n + 1, T_STRING);
if(!NOMEMP(obj)){
- char *str = OBJ_STRING(obj);
- strncpy(str, s, n);
- str[n] = '\0';
+ char *str = OBJ_STRING(obj)->data;
+ OBJ_STRING(obj)->len = n;
+ if(s){
+ memcpy(str, s, n);
+ str[n] = '\0';
+ } else {
+ memset(str, 0, n + 1);
+ }
}
return obj;
}
hfree(obj);
}
+/** Copy a string.
+ *
+ * @param obj to copy
+ */
+Sxpr string_copy(Sxpr obj){
+ return string_new_n(string_string(obj), string_length(obj));
+}
+
/** Determine if a string needs escapes when printed
* using the given flags.
*
* @param str string to check
+ * @param n string length
* @param flags print flags
* @return 1 if needs escapes, 0 otherwise
*/
-int needs_escapes(char *str, unsigned flags){
+int needs_escapes(char *str, int n, unsigned flags){
char *c;
+ int i;
int val = 0;
if(str){
- for(c=str; *c; c++){
- if(in_alpha_class(*c)) continue;
- if(in_decimal_digit_class(*c)) continue;
- if(in_class(*c, "/._+:@~-")) continue;
- val = 1;
- break;
- }
- }
- //printf("\n> val=%d str=|%s|\n", val, str);
+ for(i=0, c=str; i<n; i++, c++){
+ if(in_alpha_class(*c)) continue;
+ if(in_decimal_digit_class(*c)) continue;
+ if(in_class(*c, "/._+:@~-")) continue;
+ val = 1;
+ break;
+ }
+ }
return val;
}
+char randchar(void){
+ int r;
+ char c;
+ for( ; ; ){
+ r = rand();
+ c = (r >> 16) & 0xff;
+ if('a' <= c && c <= 'z') break;
+ }
+ return c;
+}
+
+int string_contains(char *s, int s_n, char *k, int k_n){
+ int i, n = s_n - k_n;
+ for(i=0; i < n; i++){
+ if(!memcmp(s+i, k, k_n)) return 1;
+ }
+ return 0;
+}
+
+int string_delim(char *s, int s_n, char *d, int d_n){
+ int i;
+ if(d_n < 4) return -1;
+ memset(d, 0, d_n+1);
+ for(i=0; i<3; i++){
+ d[i] = randchar();
+ }
+ for( ; i < d_n; i++){
+ if(!string_contains(s, s_n, d, i)){
+ return i;
+ }
+ d[i] = randchar();
+ }
+ return -1;
+}
+
+/** Print the bytes in a string as-is.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_raw(IOStream *io, char *str, int n){
+ int k = 0;
+ k = IOStream_write(io, str, n);
+ return k;
+}
+
+/** Print a string in counted data format.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_counted(IOStream *io, char *str, int n){
+ int k = 0;
+ k += IOStream_print(io, "%c%c%d%c",
+ c_data_open, c_data_count, n, c_data_count);
+ k += IOStream_write(io, str, n);
+ return k;
+}
+
+/** Print a string in quoted data format.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_quoted(IOStream *io, char *str, int n){
+ int k = 0;
+ char d[10];
+ int d_n;
+ d_n = string_delim(str, n, d, sizeof(d) - 1);
+ k += IOStream_print(io, "%c%c%s%c",
+ c_data_open, c_data_quote, d, c_data_quote);
+ k += IOStream_write(io, str, n);
+ k += IOStream_print(io, "%c%s%c", c_data_quote, d, c_data_quote);
+ return k;
+}
+
+/** Print a string as a quoted string.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_string(IOStream *io, char *str, int n){
+ int k = 0;
+
+ k += IOStream_print(io, "\"");
+ if(str){
+ char *s, *t;
+ for(s = str, t = str + n; s < t; s++){
+ if(*s < ' ' || *s >= 127 ){
+ switch(*s){
+ case '\a': k += IOStream_print(io, "\\a"); break;
+ case '\b': k += IOStream_print(io, "\\b"); break;
+ case '\f': k += IOStream_print(io, "\\f"); break;
+ case '\n': k += IOStream_print(io, "\\n"); break;
+ case '\r': k += IOStream_print(io, "\\r"); break;
+ case '\t': k += IOStream_print(io, "\\t"); break;
+ case '\v': k += IOStream_print(io, "\\v"); break;
+ default:
+ // Octal escape;
+ k += IOStream_print(io, "\\%o", *s);
+ break;
+ }
+ } else if(*s == c_double_quote ||
+ *s == c_single_quote ||
+ *s == c_escape){
+ k += IOStream_print(io, "\\%c", *s);
+ } else {
+ k+= IOStream_print(io, "%c", *s);
+ }
+ }
+ }
+ k += IOStream_print(io, "\"");
+ return k;
+}
+
/** Print a string to a stream, with escapes if necessary.
*
* @param io stream to print to
* @param str string
+ * @param n string length
* @param flags print flags
* @return number of bytes written
*/
-int _string_print(IOStream *io, char *str, unsigned flags){
+int _string_print(IOStream *io, char *str, int n, unsigned flags){
int k = 0;
- if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
- k += IOStream_print(io, str);
+ if((flags & PRINT_COUNTED)){
+ k = _string_print_counted(io, str, n);
+ } else if((flags & PRINT_RAW) || !needs_escapes(str, n, flags)){
+ k = _string_print_raw(io, str, n);
+ } else if(n > 50){
+ k = _string_print_quoted(io, str, n);
} else {
- k += IOStream_print(io, "\"");
- if(str){
- char *s;
- for(s = str; *s; s++){
- if(*s < ' ' || *s >= 127 ){
- switch(*s){
- case '\a': k += IOStream_print(io, "\\a"); break;
- case '\b': k += IOStream_print(io, "\\b"); break;
- case '\f': k += IOStream_print(io, "\\f"); break;
- case '\n': k += IOStream_print(io, "\\n"); break;
- case '\r': k += IOStream_print(io, "\\r"); break;
- case '\t': k += IOStream_print(io, "\\t"); break;
- case '\v': k += IOStream_print(io, "\\v"); break;
- default:
- // Octal escape;
- k += IOStream_print(io, "\\%o", *s);
- break;
- }
- } else if(*s == c_double_quote ||
- *s == c_single_quote ||
- *s == c_escape){
- k += IOStream_print(io, "\\%c", *s);
- } else {
- k+= IOStream_print(io, "%c", *s);
- }
- }
- }
- k += IOStream_print(io, "\"");
+ k = _string_print_string(io, str, n);
}
return k;
}
* @return number of bytes written
*/
int string_print(IOStream *io, Sxpr obj, unsigned flags){
- return _string_print(io, OBJ_STRING(obj), flags);
+ return _string_print(io,
+ OBJ_STRING(obj)->data,
+ OBJ_STRING(obj)->len,
+ flags);
+}
+
+int string_eq(char *s, int s_n, char *t, int t_n){
+ return (s_n == t_n) && (memcmp(s, t, s_n) == 0);
}
/** Compare an sxpr with a string for equality.
int ok = 0;
ok = eq(x,y);
if(ok) goto exit;
- ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
+ ok = has_type(y, T_STRING) &&
+ string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
+ OBJ_STRING(y)->data, OBJ_STRING(y)->len);
if(ok) goto exit;
- ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
+ ok = has_type(y, T_ATOM) &&
+ string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
+ atom_name(y), atom_length(y));
exit:
return ok;
}
void cons_free(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
- next = CDR(obj);
- objfree(CAR(obj));
- hfree(obj);
+ next = CDR(obj);
+ objfree(CAR(obj));
+ hfree(obj);
}
if(!NULLP(obj)){
- objfree(obj);
+ objfree(obj);
}
}
+/** Copy a cons. Recursively copies the car and cdr.
+ *
+ * @param obj to copy
+ */
+Sxpr cons_copy(Sxpr obj){
+ Sxpr v = ONULL;
+ Sxpr l = ONULL, x = ONONE;
+ for(l = obj; CONSP(l); l = CDR(l)){
+ x = objcopy(CAR(l));
+ if(NOMEMP(x)) goto exit;
+ x = cons_new(x, v);
+ if(NOMEMP(x)) goto exit;
+ v = x;
+ }
+ v = nrev(v);
+ exit:
+ if(NOMEMP(x)){
+ objfree(v);
+ v = ONOMEM;
+ }
+ return v;
+}
+
/** Free a cons and its cdr cells, but not the car sxprs.
* Does nothing if called on something that is not a cons.
*
void cons_free_cells(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
- next = CDR(obj);
- hfree(obj);
+ next = CDR(obj);
+ hfree(obj);
}
}
*/
Sxpr nrev(Sxpr l){
if(CONSP(l)){
- // Iterate down the cells in the list making the cdr of
- // each cell point to the previous cell. The last cell
- // is the head of the reversed list.
- Sxpr prev = ONULL;
- Sxpr cell = l;
- Sxpr next;
-
- while(1){
- next = CDR(cell);
- CDR(cell) = prev;
- if(!CONSP(next)) break;
- prev = cell;
- cell = next;
- }
- l = cell;
+ // Iterate down the cells in the list making the cdr of
+ // each cell point to the previous cell. The last cell
+ // is the head of the reversed list.
+ Sxpr prev = ONULL;
+ Sxpr cell = l;
+ Sxpr next;
+
+ while(1){
+ next = CDR(cell);
+ CDR(cell) = prev;
+ if(!CONSP(next)) break;
+ prev = cell;
+ cell = next;
+ }
+ l = cell;
}
return l;
}
-/** Print the null sxpr.
+/** Print the null sxpr.
*
* @param io stream to print to
* @param obj to print
return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
}
+/** Print an error.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int err_print(IOStream *io, Sxpr obj, unsigned flags){
+ int err = OBJ_INT(obj);
+ if(err < 0) err = -err;
+ return IOStream_print(io, "[error:%d:%s]", err, strerror(err));
+}
+
+/** Print the 'nomem' sxpr.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int nomem_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "[ENOMEM]");
+}
+
int sxprp(Sxpr obj, Sxpr name){
return CONSP(obj) && objequal(CAR(obj), name);
}
}
int sxpr_is(Sxpr obj, char *s){
- if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
- if(STRINGP(obj)) return !strcmp(string_string(obj), s);
+ if(ATOMP(obj)) return string_eq(atom_name(obj), atom_length(obj), s, strlen(s));
+ if(STRINGP(obj)) return string_eq(string_string(obj), string_length(obj), s, strlen(s));
return 0;
}
*/
static void sym_free_fn(HashTable *table, HTEntry *entry){
if(entry){
- objfree(((ObjAtom*)entry->value)->name);
- HTEntry_free(entry);
+ objfree(((ObjAtom*)entry->value)->name);
+ HTEntry_free(entry);
}
}
-
+
/** Initialize the symbol table.
*
* @return 0 on sucess, error code otherwise
if(symbols){
symbols->key_hash_fn = sym_hash_fn;
symbols->key_equal_fn = sym_equal_fn;
- symbols->entry_free_fn = sym_free_fn;
+ symbols->entry_free_fn = sym_free_fn;
return 0;
}
return -1;
Sxpr get_symbol(char *sym){
HTEntry *entry;
if(!symbols){
- if(init_symbols()) return ONOMEM;
- return ONULL;
+ if(init_symbols()) return ONOMEM;
+ return ONULL;
}
entry = HashTable_get_entry(symbols, sym);
if(entry){
Sxpr intern(char *sym){
Sxpr symbol = get_symbol(sym);
if(NULLP(symbol)){
- if(!symbols) return ONOMEM;
+ if(!symbols) return ONOMEM;
symbol = atom_new(sym);
if(!NOMEMP(symbol)){
- OBJ_ATOM(symbol)->interned = TRUE;
+ OBJ_ATOM(symbol)->interned = TRUE;
HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
}
}
/** Sxpr type. */
TypeCode type;
union {
- /** Sxpr value. */
+ /** Sxpr value. */
unsigned long ul;
- /** Pointer. */
+ /** Pointer. */
void *ptr;
} v;
} Sxpr;
-/** Sxpr type to indicate out of memory. */
-#define T_NOMEM ((TypeCode)-1)
+/** Get the integer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline unsigned long get_ul(Sxpr obj){
+ return obj.v.ul;
+}
+
+/** Get the pointer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline void * get_ptr(Sxpr obj){
+ return obj.v.ptr;
+}
+
+/** Create an sxpr containing a pointer.
+ *
+ * @param ty typecode
+ * @param val pointer
+ * @return sxpr
+ */
+static inline Sxpr obj_ptr(TypeCode ty, void *val){
+ return (Sxpr){ .type= ty, .v= { .ptr= val } };
+}
+
+/** Create an sxpr containing an integer.
+ *
+ * @param ty typecode
+ * @param val integer
+ * @return sxpr
+ */
+static inline Sxpr obj_ul(TypeCode ty, unsigned long val){
+ return (Sxpr){ .type= ty, .v= { .ul= val } };
+}
+
+/** Get the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @return type
+ */
+static inline TypeCode get_type(Sxpr obj){
+ return obj.type;
+}
+
+/** Check the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @param type to check
+ * @return 1 if has the type, 0 otherwise
+ */
+static inline int has_type(Sxpr obj, TypeCode type){
+ return get_type(obj) == type;
+}
+
+/** Compare sxprs for literal equality of type and value.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static inline int eq(Sxpr x, Sxpr y){
+ return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
+}
+
/** The 'unspecified' sxpr. */
#define T_NONE ((TypeCode)0)
/** The empty list. */
/** An error. */
#define T_ERR ((TypeCode)40)
+/** Sxpr type to indicate out of memory. */
+#define T_NOMEM ((TypeCode)41)
+
+typedef struct ObjString {
+ int len;
+ char data[];
+} ObjString;
/** An atom. */
typedef struct ObjAtom {
Sxpr cdr;
} ObjCons;
-/** A vector. */
-typedef struct ObjVector {
- int n;
- Sxpr data[0];
-} ObjVector;
-
/** Flags for sxpr printing. */
enum PrintFlags {
PRINT_RAW = 0x001,
PRINT_TYPE = 0x002,
PRINT_PRETTY = 0x004,
- PRINT_NUM = 0x008,
+ PRINT_COUNTED = 0x008,
+ PRINT_ADDR = 0x010,
};
+extern int _string_print(IOStream *io, char *str, int n, unsigned flags);
+extern int _string_print_raw(IOStream *io, char *str, int n);
+extern int _string_print_counted(IOStream *io, char *str, int n);
+extern int _string_print_quoted(IOStream *io, char *str, int n);
+extern int _string_print_string(IOStream *io, char *str, int n);
+
/** An integer sxpr.
*
* @param ty type
* @param val integer value
*/
-#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
-
-/** A pointer sxpr.
- * If the pointer is non-null, returns an sxpr containing it.
- * If the pointer is null, returns ONOMEM.
- *
- * @param ty type
- * @param val pointer
- */
-#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
-
-/** Make an integer sxpr containing a pointer.
- *
- * @param val pointer
- */
-#define PTR(val) OBJP(T_UINT, (void*)(val))
+#define OBJI(ty, val) obj_ul(ty, val)
/** Make an integer sxpr.
* @param x value
/** True constant. */
#define OTRUE OBJI(T_BOOL, 1)
+/** A pointer sxpr.
+ * If the pointer is non-null, returns an sxpr containing it.
+ * If the pointer is null, returns ONOMEM.
+ *
+ * @param ty type
+ * @param val pointer
+ */
+static inline Sxpr OBJP(int ty, void *val){
+ return (val ? obj_ptr(ty, val) : ONOMEM);
+}
+
+/** Make an integer sxpr containing a pointer.
+ *
+ * @param val pointer
+ */
+#define PTR(val) OBJP(T_UINT, (void*)(val))
+
+/** Allocate some memory and return an sxpr containing it.
+ * Returns ONOMEM if allocation failed.
+ *
+ * @param n number of bytes to allocate
+ * @param ty typecode
+ * @return sxpr
+ */
+#define halloc(_n, _ty) OBJP(_ty, allocate(_n))
+
+/** Allocate an sxpr containing a pointer to the given type.
+ *
+ * @param _ctype type (uses sizeof to determine how many bytes to allocate)
+ * @param _tycode typecode
+ * @return sxpr, ONOMEM if allocation failed
+ */
+#define HALLOC(_ctype, _tycode) halloc(sizeof(_ctype), _tycode)
+
/* Recognizers for the various sxpr types. */
#define ATOMP(obj) has_type(obj, T_ATOM)
#define BOOLP(obj) has_type(obj, T_BOOL)
/* Conversions of sxprs to their values.
* No checking is done.
*/
-#define OBJ_STRING(x) ((char*)get_ptr(x))
+#define OBJ_STRING(x) ((ObjString*)get_ptr(x))
#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
#define CDAR(x) (CDR(CAR(x)))
#define CDDR(x) (CDR(CDR(x)))
-/** Get the integer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline unsigned long get_ul(Sxpr obj){
- return obj.v.ul;
-}
-
-/** Get the pointer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline void * get_ptr(Sxpr obj){
- return obj.v.ptr;
-}
-
-/** Create an sxpr containing a pointer.
- *
- * @param type typecode
- * @param val pointer
- * @return sxpr
- */
-static inline Sxpr obj_ptr(TypeCode type, void *val){
- return (Sxpr){ type: type, v: { ptr: val } };
-}
-
-/** Create an sxpr containing an integer.
- *
- * @param type typecode
- * @param val integer
- * @return sxpr
- */
-static inline Sxpr obj_ul(TypeCode type, unsigned long val){
- return (Sxpr){ type: type, v: { ul: val } };
-}
-
-/** Get the type of an sxpr.
- *
- * @param obj sxpr
- * @return type
- */
-static inline TypeCode get_type(Sxpr obj){
- return obj.type;
-}
-
-/** Check the type of an sxpr.
- *
- * @param obj sxpr
- * @param type to check
- * @return 1 if has the type, 0 otherwise
- */
-static inline int has_type(Sxpr obj, TypeCode type){
- return get_type(obj) == type;
-}
-
-/** Compare sxprs for literal equality of type and value.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-static inline int eq(Sxpr x, Sxpr y){
- return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
-}
-
/** Checked version of CAR
*
* @param x sxpr
return (CONSP(x) ? CDR(x) : ONULL);
}
-/** Allocate some memory and return an sxpr containing it.
- * Returns ONOMEM if allocation failed.
- *
- * @param n number of bytes to allocate
- * @param ty typecode
- * @return sxpr
- */
-static inline Sxpr halloc(size_t n, TypeCode ty){
- return OBJP(ty, allocate(n));
-}
-
-/** Allocate an sxpr containing a pointer to the given type.
- *
- * @param ty type (uses sizeof to determine how many bytes to allocate)
- * @param code typecode
- * @return sxpr, ONOMEM if allocation failed
- */
-#define HALLOC(ty, code) halloc(sizeof(ty), code)
-
typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
typedef int ObjEqualFn(Sxpr obj, Sxpr other);
typedef void ObjFreeFn(Sxpr obj);
+typedef Sxpr ObjCopyFn(Sxpr obj);
/** An sxpr type definition. */
typedef struct SxprType {
ObjPrintFn *print;
ObjEqualFn *equal;
ObjFreeFn *free;
+ ObjCopyFn *copy;
} SxprType;
extern int objprint(IOStream *io, Sxpr x, unsigned flags);
extern int objequal(Sxpr x, Sxpr y);
extern void objfree(Sxpr x);
+extern Sxpr objcopy(Sxpr x);
extern void cons_free_cells(Sxpr obj);
extern Sxpr intern(char *s);
extern Sxpr atom_new(char *name);
extern char * atom_name(Sxpr obj);
+extern int atom_length(Sxpr obj);
extern Sxpr string_new(char *s);
+extern Sxpr string_new_n(char *s, int n);
extern char * string_string(Sxpr obj);
extern int string_length(Sxpr obj);
#define k_true "true"
#define k_false "false"
-#define c_var '$'
#define c_escape '\\'
#define c_single_quote '\''
#define c_double_quote '"'
#define c_string_open c_double_quote
#define c_string_close c_double_quote
-#define c_data_open '['
-#define c_data_close ']'
-#define c_binary '*'
+
+#define c_data_open '<'
+#define c_data_quote '<'
+#define c_data_count '*'
+//#define c_data_open '['
+//#define c_data_close ']'
+//#define c_binary '*'
+
+#define c_var '$'
#define c_eval '!'
#define c_concat_open '{'
#define c_concat_close '}'
/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
# include <errno.h>
#endif
+#include "sys_net.h"
+
#include "iostream.h"
#include "lexis.h"
#include "sxpr_parser.h"
* @author Mike Wray <mike.wray@hpl.hp.com>
*/
+#ifdef DEBUG
#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
+#else
+#define dprintf(fmt, args...) do{ }while(0)
+#endif
+
#undef printf
#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
-static void reset(Parser *z);
-static int inputchar(Parser *p, char c);
-static int savechar(Parser *p, char c);
-extern void parse_error(Parser *in);
-extern void parse_error_id(Parser *in, ParseErrorId id);
-
-static int begin_start(Parser *p, char c);
static int state_start(Parser *p, char c);
-static int end_start(Parser *p);
-
-static int begin_comment(Parser *p, char c);
-static int state_comment(Parser *p, char c);
-static int end_comment(Parser *p);
-
-static int begin_string(Parser *p, char c);
-static int state_string(Parser *p, char c);
-static int end_string(Parser *p);
-static int state_escape(Parser *p, char c);
-static int state_octal(Parser *p, char c);
-static int state_hex(Parser *p, char c);
-
-static int begin_atom(Parser *p, char c);
-static int state_atom(Parser *p, char c);
-static int end_atom(Parser *p);
-
-static int state_list(Parser *p, char c);
-static int begin_list(Parser *p, char c);
-static int end_list(Parser *p);
+static int begin_start(Parser *p, char c);
/** Print a parse error.
*
* @param in parser
* @param msg format followed by printf arguments
*/
-void eprintf(Parser *in, char *msg, ...){
+static void eprintf(Parser *in, char *msg, ...){
va_list args;
if(in->error_out){
va_start(args, msg);
* @param in parser
* @param msg format followed by printf arguments
*/
-void wprintf(Parser *in, char *msg, ...){
+static void wprintf(Parser *in, char *msg, ...){
va_list args;
if(in->error_out){
va_start(args, msg);
/** Record defining the message for a parse error. */
typedef struct {
- ParseErrorId id;
- char *message;
+ ParseErrorId id;
+ char *message;
} ParseError;
/** Format for printing parse error messages. */
/** Message catalog for the parse error codes. */
static ParseError catalog[] = {
- { PARSE_ERR_UNSPECIFIED, "unspecified error" },
- { PARSE_ERR_NOMEM, "out of memory" },
- { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
- { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
- { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
- { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
- { 0, NULL }
+ { PARSE_ERR_UNSPECIFIED, "unspecified error" },
+ { PARSE_ERR_NOMEM, "out of memory" },
+ { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
+ { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
+ { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
+ { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
+ { 0, NULL }
};
/** Number of entries in the message catalog. */
const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
-void ParserState_free(ParserState *z){
- if(!z) return;
- objfree(z->val);
- deallocate(z);
+/** Set the parser error stream.
+ * Parse errors are reported on the the error stream if it is non-null.
+ *
+ * @param z parser
+ * @param error_out error stream
+ */
+void Parser_set_error_stream(Parser *z, IOStream *error_out){
+ z->error_out = error_out;
}
-int ParserState_new(ParserStateFn *fn, char *name,
- ParserState *parent, ParserState **val){
- int err = 0;
- ParserState *z;
- z = ALLOCATE(ParserState);
- if(z){
- z->name = name;
- z->fn = fn;
- z->parent = parent;
- z->val = ONULL;
- } else {
- err = -ENOMEM;
+/** Get the parser error message for an error code.
+ *
+ * @param id error code
+ * @return error message (empty string if the code is unknown)
+ */
+static char *get_message(ParseErrorId id){
+ int i;
+ for(i = 0; i < catalog_n; i++){
+ if(id == catalog[i].id){
+ return catalog[i].message;
+ }
}
- if(!err) *val = z;
- return err;
+ return "";
}
-/** Free a parser.
- * No-op if the parser is null.
+/** Get the line number.
*
- * @param z parser
+ * @param in parser
*/
-void Parser_free(Parser *z){
- if(!z) return;
- objfree(z->val);
- z->val = ONONE;
- deallocate(z);
+static int get_line(Parser *in){
+ return in->line_no;
}
-/** Create a new parser. The error stream defaults to null.
+/** Get the column number.
+ *
+ * @param in parser
*/
-Parser * Parser_new(void){
- Parser *z = ALLOCATE(Parser);
- int err = -ENOMEM;
-
- if(!z) goto exit;
- err = 0;
- reset(z);
- exit:
- if(err){
- Parser_free(z);
- z = NULL;
- }
- return z;
+static int get_column(Parser *in){
+ return in->char_no;
}
-/** Get the next character.
- * Records the character read in the parser,
- * and sets the line and character counts.
+/** Get the line number the current token started on.
+ *
+ * @param in parser
+ */
+static int get_tok_line(Parser *in){
+ return in->tok_begin_line;
+}
+
+/** Get the column number the current token started on.
+ *
+ * @param in parser
+ */
+static int get_tok_column(Parser *in){
+ return in->tok_begin_char;
+}
+
+/** Return the current token.
+ * The return value points at the internal buffer, so
+ * it must not be modified (or freed). Use copy_token() if you need a copy.
*
* @param p parser
- * @return error flag: 0 on success, non-zero on error
+ * @return token
*/
-static int inputchar(Parser *p, char c){
- int err = 0;
- if(c=='\n'){
- p->line_no++;
- p->char_no = 0;
- } else {
- p->char_no++;
+char *peek_token(Parser *p){
+ return p->tok;
+}
+
+int token_len(Parser *p){
+ return p->tok_end - p->tok;
+}
+
+/** Return a copy of the current token.
+ * The returned value should be freed when finished with.
+ *
+ * @param p parser
+ * @return copy of token
+ */
+char *copy_token(Parser *p){
+ int n = token_len(p);
+ char *buf = allocate(n + 1);
+ if(buf){
+ memcpy(buf, peek_token(p), n);
+ buf[n] = '\0';
}
- return err;
+ return buf;
}
-static int savechar(Parser *p, char c){
- int err = 0;
- if(p->buf_i >= p->buf_n){
- err = -ENOMEM;
- goto exit;
+void new_token(Parser *p){
+ memset(p->buf, 0, p->buf_end - p->buf);
+ p->tok = p->buf;
+ p->tok_end = p->tok;
+ p->tok_begin_line = p->line_no;
+ p->tok_begin_char = p->char_no;
+}
+
+/** Report a parse error.
+ * Does nothing if the error stream is null or there is no error.
+ *
+ * @param in parser
+ */
+static void report_error(Parser *in){
+ if(in->error_out && in->err){
+ char *msg = get_message(in->err);
+ char *tok = peek_token(in);
+ IOStream_print(in->error_out, PARSE_ERR_FMT,
+ get_tok_line(in), get_tok_column(in), msg);
+ if(tok && tok[0]){
+ IOStream_print(in->error_out, " '%s'", tok);
+ }
+ IOStream_print(in->error_out, "\n");
}
- p->buf[p->buf_i] = c;
- p->buf_i++;
- exit:
- return err;
}
-int Parser_input_char(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- //skip;
- } else {
- inputchar(p, c);
+/** Get the error message for the current parse error code.
+ * Does nothing if there is no error.
+ *
+ * @param in parser
+ * @param buf where to place the message
+ * @param n maximum number of characters to place in buf
+ * @return current error code (zero for no error)
+ */
+int Parser_error_message(Parser *in, char *buf, int n){
+ if(in->err){
+ char *msg = get_message(in->err);
+ snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in),
+ get_tok_column(in), msg);
}
- if(!p->state){
- err = begin_start(p, c);
- if(err) goto exit;
+ return in->err;
+}
+
+/** Flag a parse error. All subsequent reads will fail.
+ * Does not change the parser error code if it is already set.
+ *
+ * @param in parser
+ * @param id error code
+ */
+int Parser_error_id(Parser *in, ParseErrorId id){
+ if(!in->err){
+ in->err = id;
+ report_error(in);
}
- err = p->state->fn(p, c);
- exit:
- return err;
+ return -EINVAL;
}
-int Parser_input_eof(Parser *p){
- int err = 0;
- p->eof = 1;
- err = Parser_input_char(p, IOSTREAM_EOF);
- return err;
+/** Flag an unspecified parse error.
+ *
+ * @param in parser
+ */
+int Parser_error(Parser *in){
+ return Parser_error_id(in, PARSE_ERR_INVALID_SYNTAX);
}
-int Parser_input(Parser *p, char *buf, int buf_n){
- int err = 0;
- int i = 0;
- if(buf_n <= 0){
- err = Parser_input_eof(p);
- goto exit;
- }
- for(i = 0; i<buf_n; i++){
- err = Parser_input_char(p, buf[i]);
- if(err) goto exit;
- }
- exit:
- err = (err < 0 ? err : buf_n);
- return err;
+/** Test if the parser's error flag is set.
+ *
+ * @param in parser
+ * @return 1 if set, 0 otherwise
+ */
+int Parser_has_error(Parser *in){
+ return (in->err > 0);
}
-int Parser_push(Parser *p, ParserStateFn *fn, char *name){
- int err = 0;
- err = ParserState_new(fn, name, p->state, &p->state);
+/** Test if the parser is at end of input.
+ *
+ * @param in parser
+ * @return 1 if at EOF, 0 otherwise
+ */
+int Parser_at_eof(Parser *p){
+ return p->eof;
+}
+
+void ParserState_free(ParserState *z){
+ if(!z) return;
+ objfree(z->val);
+ deallocate(z);
+}
+
+int ParserState_new(ParserStateFn *fn, char *name,
+ ParserState *parent, ParserState **val){
+ int err = -ENOMEM;
+ ParserState *z;
+ z = ALLOCATE(ParserState);
+ if(!z) goto exit;
+ z->name = name;
+ z->fn = fn;
+ z->parent = parent;
+ z->val = ONULL;
+ err = 0;
+ exit:
+ *val = (err ? NULL : z);
return err;
}
-
-int Parser_pop(Parser *p){
- int err = 0;
+
+void Parser_pop(Parser *p){
ParserState *s = p->state;
+ if(!s) return;
p->state = s->parent;
if (p->start_state == s) {
p->start_state = NULL;
}
ParserState_free(s);
- return err;
}
+/** Free a parser.
+ * No-op if the parser is null.
+ *
+ * @param z parser
+ */
+void Parser_free(Parser *z){
+ if(!z) return;
+ // Hmmm. Need to free states, but careful about double free of values.
+ while(z->state){
+ objfree(z->state->val);
+ Parser_pop(z);
+ }
+ if(z->buf) deallocate(z->buf);
+ objfree(z->val);
+ z->val = ONONE;
+ deallocate(z);
+}
+
+int Parser_push(Parser *p, ParserStateFn *fn, char *name){
+ return ParserState_new(fn, name, p->state, &p->state);
+}
+
int Parser_return(Parser *p){
int err = 0;
Sxpr val = ONONE;
}
val = p->state->val;
p->state->val = ONONE;
- err = Parser_pop(p);
- if(err) goto exit;
+ Parser_pop(p);
if(p->state){
err = cons_push(&p->state->val, val);
} else {
return err;
}
-/** Determine if a character is a separator.
+/** Reset the fields of a parser to initial values.
*
- * @param p parser
- * @param c character to test
- * @return 1 if a separator, 0 otherwise
+ * @param z parser
*/
-static int is_separator(Parser *p, char c){
- return in_sep_class(c);
+static void reset(Parser *z){
+ // leave flags
+ // leave error_out
+ while(z->state){
+ Parser_pop(z);
+ }
+ z->val = ONONE;
+ z->eof = 0;
+ z->err = 0;
+ z->line_no = 1;
+ z->char_no = 0;
+ memset(z->buf, 0, z->buf_end - z->buf);
+ z->tok = z->buf;
+ z->tok_end = z->tok;
+ z->tok_begin_line = 0;
+ z->tok_begin_char = 0;
+ z->start_state = NULL;
}
-/** Return the current token.
- * The return value points at the internal buffer, so
- * it must not be modified (or freed). Use copy_token() if you need a copy.
- *
- * @param p parser
- * @return token
+/** Create a new parser. The error stream defaults to null.
*/
-char *peek_token(Parser *p){
- return p->buf;
+Parser * Parser_new(void){
+ Parser *z = ALLOCATE(Parser);
+ int n = PARSER_BUF_SIZE;
+ int err = -ENOMEM;
+
+ if(!z) goto exit;
+ z->buf = allocate(n);
+ if(!z->buf) goto exit;
+ err = 0;
+ z->buf_end = z->buf + n;
+ z->begin = begin_start;
+ reset(z);
+ exit:
+ if(err){
+ Parser_free(z);
+ z = NULL;
+ }
+ return z;
}
-/** Return a copy of the current token.
- * The returned value should be freed when finished with.
+/** Get the next character.
+ * Records the character read in the parser,
+ * and sets the line and character counts.
*
* @param p parser
- * @return copy of token
+ * @return error flag: 0 on success, non-zero on error
*/
-char *copy_token(Parser *p){
- return strdup(peek_token(p));
-}
-
-static int do_intern(Parser *p){
+static int input_char(Parser *p, char c){
int err = 0;
- Sxpr obj = intern(peek_token(p));
- if(NOMEMP(obj)){
- err = -ENOMEM;
+ if(c=='\n'){
+ p->line_no++;
+ p->char_no = 0;
} else {
- p->state->val = obj;
+ p->char_no++;
}
return err;
}
-static int do_string(Parser *p){
+int save_char(Parser *p, char c){
+ int err = 0;
+ if(p->tok_end >= p->buf_end){
+ int buf_n = (p->buf_end - p->buf) + PARSER_BUF_INCREMENT;
+ char *buf = allocate(buf_n);
+ if(!buf){
+ err = -ENOMEM;
+ goto exit;
+ }
+ memcpy(buf, p->buf, p->tok_end - p->buf);
+ p->buf_end = buf + buf_n;
+ p->tok = buf + (p->tok - p->buf);
+ p->tok_end = buf + (p->tok_end - p->buf);
+ deallocate(p->buf);
+ p->buf = buf;
+ }
+ *p->tok_end++ = c;
+ exit:
+ return err;
+}
+
+/** Determine if a character is a separator.
+ *
+ * @param p parser
+ * @param c character to test
+ * @return 1 if a separator, 0 otherwise
+ */
+static int is_separator(Parser *p, char c){
+ return in_sep_class(c);
+}
+
+int Parser_set_value(Parser *p, Sxpr obj){
int err = 0;
- Sxpr obj;
- obj = string_new(peek_token(p));
if(NOMEMP(obj)){
err = -ENOMEM;
} else {
}
return err;
}
+
+int Parser_intern(Parser *p){
+ Sxpr obj = intern(peek_token(p));
+ return Parser_set_value(p, obj);
+}
-void newtoken(Parser *p){
- memset(p->buf, 0, p->buf_n);
- p->buf_i = 0;
- p->tok_begin_line = p->line_no;
- p->tok_begin_char = p->char_no;
+int Parser_atom(Parser *p){
+ Sxpr obj = atom_new(peek_token(p));
+ return Parser_set_value(p, obj);
+}
+
+int Parser_string(Parser *p){
+ Sxpr obj = string_new_n(peek_token(p), token_len(p));
+ return Parser_set_value(p, obj);
+}
+
+int Parser_data(Parser *p){
+ Sxpr obj = string_new_n(peek_token(p), token_len(p));
+ return Parser_set_value(p, obj);
+}
+
+int Parser_uint(Parser *p){
+ unsigned int x = htonl(*(unsigned int *)peek_token(p));
+ return Parser_set_value(p, OINT(x));
}
-int get_escape(char c, char *d){
+static int get_escape(char c, char *d){
int err = 0;
switch(c){
case 'a': *d = '\a'; break;
Sxpr Parser_get_val(Parser *p){
Sxpr v = ONONE;
if(CONSP(p->val)){
- v = CAR(p->val);
- p->val = CDR(p->val);
- } else if (CONSP(p->start_state->val)){
+ } else if (p->start_state && CONSP(p->start_state->val)){
p->val = p->start_state->val;
p->val = nrev(p->val);
p->start_state->val = ONULL;
- v = CAR(p->val);
- p->val = CDR(p->val);
- }
+ } else {
+ goto exit;
+ }
+ Sxpr w = p->val;
+ v = CAR(w);
+ p->val = CDR(w);
+ hfree(w);
+ exit:
return v;
}
}
return v;
}
-
-int begin_start(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_start, "start");
- if(err) goto exit;
- p->start_state = p->state;
- exit:
- return err;
-}
-int state_start(Parser *p, char c){
+static int state_comment(Parser *p, char c){
int err = 0;
- if(at_eof(p)){
- err = end_start(p);
- } else if(in_space_class(c)){
- //skip
- } else if(in_comment_class(c)){
- begin_comment(p, c);
- } else if(c == c_list_open){
- begin_list(p, c);
- } else if(c == c_list_close){
- parse_error(p);
- err = -EINVAL;
- } else if(in_string_quote_class(c)){
- begin_string(p, c);
- } else if(in_printable_class(c)){
- begin_atom(p, c);
- } else if(c == 0x04){
- //ctrl-D, EOT: end-of-text.
- Parser_input_eof(p);
+ if(c == '\n' || Parser_at_eof(p)){
+ Parser_pop(p);
} else {
- parse_error(p);
- err = -EINVAL;
+ err = input_char(p, c);
}
return err;
}
-int end_start(Parser *p){
- int err = 0;
- err = Parser_return(p);
- return err;
-}
-
-int begin_comment(Parser *p, char c){
+static int begin_comment(Parser *p, char c){
int err = 0;
err = Parser_push(p, state_comment, "comment");
if(err) goto exit;
- err = inputchar(p, c);
- exit:
- return err;
-}
-
-int state_comment(Parser *p, char c){
- int err = 0;
- if(c == '\n' || at_eof(p)){
- err = end_comment(p);
- } else {
- err = inputchar(p, c);
- }
- return err;
-}
-
-int end_comment(Parser *p){
- return Parser_pop(p);
-}
-
-int begin_string(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_string, "string");
- if(err) goto exit;
- newtoken(p);
- p->state->delim = c;
- exit:
- return err;
-}
-
-int state_string(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == p->state->delim){
- err = end_string(p);
- } else if(c == '\\'){
- err = Parser_push(p, state_escape, "escape");
- } else {
- err = savechar(p, c);
- }
- return err;
-}
-
-int end_string(Parser *p){
- int err = 0;
- err = do_string(p);
- if(err) goto exit;
- err = Parser_return(p);
+ err = input_char(p, c);
exit:
return err;
}
-int state_escape(Parser *p, char c){
+static int end_string(Parser *p){
int err = 0;
- char d;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- }
- if(get_escape(c, &d) == 0){
- err = savechar(p, d);
- if(err) goto exit;
- err = Parser_pop(p);
- } else if(c == 'x'){
- p->state->fn = state_hex;
- p->state->ival = 0;
- p->state->count = 0;
- } else {
- p->state->fn = state_octal;
- p->state->ival = 0;
- p->state->count = 0;
- err = Parser_input_char(p, c);
- }
+ err = Parser_string(p);
+ if(err) goto exit;
+ err = Parser_return(p);
exit:
return err;
}
-int octaldone(Parser *p){
+static int octaldone(Parser *p){
int err = 0;
char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
+ Parser_pop(p);
err = Parser_input_char(p, d);
- exit:
return err;
}
-int octaldigit(Parser *p, char c){
+static int octaldigit(Parser *p, int d){
int err = 0;
p->state->ival *= 8;
- p->state->ival += c - '0';
+ p->state->ival += d;
p->state->count++;
if(err) goto exit;
if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
+ err = Parser_error(p);
goto exit;
}
if(p->state->count == 3){
return err;
}
-int state_octal(Parser *p, char c){
+static int state_octal(Parser *p, char c){
int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
+ if(Parser_at_eof(p)){
+ err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
goto exit;
} else if('0' <= c && c <= '7'){
- err = octaldigit(p, c);
+ err = octaldigit(p, c - '0');
} else {
err = octaldone(p);
if(err) goto exit;
return err;
}
-int hexdone(Parser *p){
+static int hexdone(Parser *p){
int err = 0;
char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
+ Parser_pop(p);
err = Parser_input_char(p, d);
- exit:
return err;
}
-int hexdigit(Parser *p, char c, char d){
+static int hexdigit(Parser *p, int d){
int err = 0;
p->state->ival *= 16;
- p->state->ival += c - d;
+ p->state->ival += d;
p->state->count++;
if(err) goto exit;
if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
+ err = Parser_error(p);
goto exit;
}
if(p->state->count == 2){
return err;
}
-int state_hex(Parser *p, char c){
+static int state_hex(Parser *p, char c){
int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
+ if(Parser_at_eof(p)){
+ err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
goto exit;
} else if('0' <= c && c <= '9'){
- err = hexdigit(p, c, '0');
+ err = hexdigit(p, c - '0');
} else if('A' <= c && c <= 'F'){
- err = hexdigit(p, c, 'A');
+ err = hexdigit(p, c - 'A' + 10);
} else if('a' <= c && c <= 'f'){
- err = hexdigit(p, c, 'a');
+ err = hexdigit(p, c - 'a' + 10);
} else if(p->state->count){
- err =hexdone(p);
+ err = hexdone(p);
if(err) goto exit;
Parser_input_char(p, c);
}
return err;
}
-int begin_atom(Parser *p, char c){
+static int state_escape(Parser *p, char c){
int err = 0;
- err = Parser_push(p, state_atom, "atom");
+ char d;
+ if(Parser_at_eof(p)){
+ err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ goto exit;
+ }
+ if(get_escape(c, &d) == 0){
+ err = save_char(p, d);
+ if(err) goto exit;
+ Parser_pop(p);
+ } else if(c == 'x'){
+ p->state->fn = state_hex;
+ p->state->ival = 0;
+ p->state->count = 0;
+ } else {
+ p->state->fn = state_octal;
+ p->state->ival = 0;
+ p->state->count = 0;
+ err = Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+static int state_string(Parser *p, char c){
+ int err = 0;
+ if(Parser_at_eof(p)){
+ err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ } else if(c == p->state->delim){
+ err = end_string(p);
+ } else if(c == '\\'){
+ err = Parser_push(p, state_escape, "escape");
+ } else {
+ err = save_char(p, c);
+ }
+ return err;
+}
+
+static int begin_string(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_string, "string");
+ if(err) goto exit;
+ new_token(p);
+ p->state->delim = c;
+ exit:
+ return err;
+}
+
+static int end_atom(Parser *p){
+ int err = 0;
+ err = Parser_atom(p);
if(err) goto exit;
- newtoken(p);
- err = savechar(p, c);
+ err = Parser_return(p);
exit:
return err;
}
-int state_atom(Parser *p, char c){
+static int state_atom(Parser *p, char c){
int err = 0;
- if(at_eof(p)){
+ if(Parser_at_eof(p)){
err = end_atom(p);
} else if(is_separator(p, c) ||
in_space_class(c) ||
if(err) goto exit;
err = Parser_input_char(p, c);
} else {
- err = savechar(p, c);
+ err = save_char(p, c);
}
exit:
return err;
}
-int end_atom(Parser *p){
+static int begin_atom(Parser *p, char c){
int err = 0;
- err = do_intern(p);
+ err = Parser_push(p, state_atom, "atom");
if(err) goto exit;
- err = Parser_return(p);
+ new_token(p);
+ err = save_char(p, c);
exit:
return err;
}
-int state_list(Parser *p, char c){
+static int end_data(Parser *p){
int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == c_list_close){
- p->state->val = nrev(p->state->val);
- err = end_list(p);
- } else {
- err = state_start(p, c);
- }
+ err = Parser_data(p);
+ if(err) goto exit;
+ err = Parser_return(p);
+ exit:
return err;
-
-}
-
-int begin_list(Parser *p, char c){
- return Parser_push(p, state_list, "list");
-}
-
-int end_list(Parser *p){
- return Parser_return(p);
-}
-
-/** Reset the fields of a parser to initial values.
- *
- * @param z parser
- */
-static void reset(Parser *z){
- IOStream *error_out = z->error_out;
- int flags = z->flags;
- memzero(z, sizeof(Parser));
- z->buf_n = sizeof(z->buf) - 1;
- z->buf_i = 0;
- z->line_no = 1;
- z->char_no = 0;
- z->error_out = error_out;
- z->flags = flags;
-}
-
-/** Set the parser error stream.
- * Parse errors are reported on the the error stream if it is non-null.
- *
- * @param z parser
- * @param error_out error stream
- */
-void set_error_stream(Parser *z, IOStream *error_out){
- if(z){
- z->error_out = error_out;
- }
}
-/** Get the parser error message for an error code.
- *
- * @param id error code
- * @return error message (empty string if the code is unknown)
- */
-static char *get_message(ParseErrorId id){
- int i;
- for(i=0; i<catalog_n; i++){
- if(id == catalog[i].id){
- return catalog[i].message;
+static int counted_data(Parser *p, char c){
+ int err = 0;
+ err = save_char(p, c);
+ if(err) goto exit;
+ if(token_len(p) == p->state->count){
+ err = end_data(p);
}
- }
- return "";
-}
-
-/** Get the line number.
- *
- * @param in parser
- */
-int get_line(Parser *in){
- return in->line_no;
-}
-
-/** Get the column number.
- *
- * @param in parser
- */
-int get_column(Parser *in){
- return in->char_no;
+ exit:
+ return err;
}
-/** Get the line number the current token started on.
- *
- * @param in parser
- */
-int get_tok_line(Parser *in){
- return in->tok_begin_line;
+static int counted_data_count(Parser *p, char c){
+ int err = 0;
+ if(c == p->state->delim){
+ new_token(p);
+ p->state->count = p->state->ival;
+ p->state->fn = counted_data;
+ } else if('0' <= c && c <= '9'){
+ p->state->ival *= 10;
+ p->state->ival += c - '0';
+ } else {
+ err = -EINVAL;
+ }
+ return err;
}
-/** Get the column number the current token started on.
- *
- * @param in parser
- */
-int get_tok_column(Parser *in){
- return in->tok_begin_char;
+static int quoted_data(Parser *p, char c){
+ int err = 0;
+ int count = p->state->count;
+ err = save_char(p, c);
+ if(err) goto exit;
+ // Check that buf is longer than delim and
+ // ends with delim. If so, trim delim off and return.
+ if((token_len(p) >= count) &&
+ !memcmp(p->tok_end - count, p->buf, count)){
+ p->tok_end -= count;
+ end_data(p);
+ }
+ exit:
+ return err;
}
-/** Report a parse error.
- * Does nothing if the error stream is null or there is no error.
- *
- * @param in parser
- */
-static void report_error(Parser *in){
- if(in->error_out && in->err){
- char *msg = get_message(in->err);
- char *tok = peek_token(in);
- IOStream_print(in->error_out, PARSE_ERR_FMT,
- get_tok_line(in), get_tok_column(in), msg);
- if(tok && tok[0]){
- IOStream_print(in->error_out, " '%s'", tok);
+static int quoted_data_delim(Parser *p, char c){
+ // Saves the delim in the token buffer.
+ int err = 0;
+ err = save_char(p, c);
+ if(err) goto exit;
+ if(c == p->state->delim){
+ p->state->fn = quoted_data;
+ p->state->count = token_len(p);
+ // Advance the token pointer past the delim.
+ p->tok = p->tok_end;
}
- IOStream_print(in->error_out, "\n");
- }
+ exit:
+ return err;
}
-/** Get the error message for the current parse error code.
- * Does nothing if there is no error.
- *
- * @param in parser
- * @param buf where to place the message
- * @param n maximum number of characters to place in buf
- * @return current error code (zero for no error)
- */
-int parse_error_message(Parser *in, char *buf, int n){
- if(in->err){
- char *msg = get_message(in->err);
- snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
+static int state_data(Parser *p, char c){
+ // Quoted data:
+ // <<delim< anything not containing delimiter<delim<
+ // Where 'delim' is anything not containing '<'.
+ // Counted data:
+ // <*nnn..* N bytes
+ // Where nnn... is N in decimal (
+ int err = 0;
+ switch(c){
+ case c_data_count:
+ p->state->delim = c;
+ p->state->fn = counted_data_count;
+ p->state->ival = 0;
+ new_token(p);
+ break;
+ case c_data_quote:
+ p->state->delim = c;
+ p->state->fn = quoted_data_delim;
+ new_token(p);
+ err = save_char(p, c);
+ break;
+ default:
+ err = Parser_error(p);
+ break;
}
- return in->err;
+ return err;
}
-/** Flag an unspecified parse error. All subsequent reads will fail.
- *
- * @param in parser
- */
-void parse_error(Parser *in){
- parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
+static int begin_data(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_data, "data");
+ if(err) goto exit;
+ new_token(p);
+ exit:
+ return err;
}
-/** Flag a parse error. All subsequent reads will fail.
- * Does not change the parser error code if it is already set.
- *
- * @param in parser
- * @param id error code
- */
-void parse_error_id(Parser *in, ParseErrorId id){
- if(!in->err){
- in->err = id;
- report_error(in);
+static int state_list(Parser *p, char c){
+ int err = 0;
+ dprintf(">\n");
+ if(Parser_at_eof(p)){
+ err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ } else if(c == c_list_close){
+ p->state->val = nrev(p->state->val);
+ err = Parser_return(p);
+ } else {
+ err = state_start(p, c);
}
+ dprintf("< err=%d\n", err);
+ return err;
+
}
-/** Test if the parser's error flag is set.
- *
- * @param in parser
- * @return 1 if set, 0 otherwise
- */
-int has_error(Parser *in){
- return (in->err > 0);
-}
-
-/** Test if the parser is at end of input.
- *
- * @param in parser
- * @return 1 if at EOF, 0 otherwise
- */
-int at_eof(Parser *p){
- return p->eof;
+static int begin_list(Parser *p, char c){
+ return Parser_push(p, state_list, "list");
}
-#ifdef SXPR_PARSER_MAIN
-/* Stuff for standalone testing. */
-
-#include "file_stream.h"
-#include "string_stream.h"
-
-extern int stringof(Sxpr exp, char **s);
-int child_string(Sxpr exp, Sxpr key, char **s){
+static int state_start(Parser *p, char c){
int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = stringof(val, s);
+ dprintf(">\n");
+ if(Parser_at_eof(p)){
+ err = Parser_return(p);
+ } else if(in_space_class(c)){
+ //skip
+ } else if(in_comment_class(c)){
+ begin_comment(p, c);
+ } else if(c == c_list_open){
+ begin_list(p, c);
+ } else if(c == c_list_close){
+ err = Parser_error(p);
+ } else if(in_string_quote_class(c)){
+ begin_string(p, c);
+ } else if(c == c_data_open){
+ begin_data(p, c);
+ } else if(in_printable_class(c)){
+ begin_atom(p, c);
+ } else if(c == 0x04){
+ //ctrl-D, EOT: end-of-text.
+ Parser_input_eof(p);
+ } else {
+ err = Parser_error(p);
+ }
+ dprintf("< err=%d\n", err);
return err;
}
-extern int intof(Sxpr exp, int *v);
-int child_int(Sxpr exp, Sxpr key, int *v){
+int begin_start(Parser *p, char c){
int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = intof(val, v);
+ dprintf(">\n");
+ err = Parser_push(p, state_start, "start");
+ if(err) goto exit;
+ p->start_state = p->state;
+ exit:
+ dprintf("< err=%d\n", err);
return err;
}
-int eval_vnet(Sxpr exp){
+int Parser_input_char(Parser *p, char c){
int err = 0;
- Sxpr oid = intern("id");
- int id;
- err = child_int(exp, oid, &id);
- if(err) goto exit;
- dprintf("> vnet id=%d\n", id);
- exit:
- dprintf("< err=%d\n", err);
+ if(Parser_at_eof(p)){
+ //skip;
+ } else {
+ input_char(p, c);
+ }
+ if(!p->state){
+ err = p->begin(p, c);
+ if(err) goto exit;
+ }
+ err = p->state->fn(p, c);
+ exit:
return err;
}
-int eval_connect(Sxpr exp){
+int Parser_input_eof(Parser *p){
int err = 0;
- Sxpr ovif = intern("vif");
- Sxpr ovnet = intern("vnet");
- char *vif;
- int vnet;
-
- err = child_string(exp, ovif, &vif);
- if(err) goto exit;
- err = child_int(exp, ovnet, &vnet);
- if(err) goto exit;
- dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
- exit:
- dprintf("< err=%d\n", err);
+ p->eof = 1;
+ err = Parser_input_char(p, IOSTREAM_EOF);
return err;
}
-int eval(Sxpr exp){
+int Parser_input(Parser *p, char *buf, int buf_n){
int err = 0;
- Sxpr oconnect = intern("connect");
- Sxpr ovnet = intern("vnet");
-
- if(sxpr_elementp(exp, ovnet)){
- err = eval_vnet(exp);
- } else if(sxpr_elementp(exp, oconnect)){
- err = eval_connect(exp);
- } else {
- err = -EINVAL;
+ int i = 0;
+ dprintf("> |%s|\n", buf);
+ if(buf_n <= 0){
+ err = Parser_input_eof(p);
+ goto exit;
}
+ for(i = 0; i < buf_n; i++){
+ err = Parser_input_char(p, buf[i]);
+ if(err) goto exit;
+ }
+ exit:
+ err = (err < 0 ? err : buf_n);
+ dprintf("< err=%d\n", err);
return err;
}
+#ifdef SXPR_PARSER_MAIN
+/* Stuff for standalone testing. */
+
+#include "file_stream.h"
+//#include "string_stream.h"
+
/** Main program for testing.
* Parses input and prints it.
*
char buf[1024];
int k;
Sxpr obj;
- //Sxpr l, x;
int i = 0;
pin = Parser_new();
- set_error_stream(pin, iostdout);
+ Parser_set_error_stream(pin, iostdout);
dprintf("> parse...\n");
while(1){
- k = fread(buf, 1, 1, stdin);
+ k = fread(buf, 1, 100, stdin);
+ if(k>=0){
+ buf[k+1] = '\0';
+ }
err = Parser_input(pin, buf, k);
while(Parser_ready(pin)){
obj = Parser_get_val(pin);
}
if(k <= 0) break;
}
-/* obj = Parser_get_all(pin); */
-/* for(l = obj ; CONSP(l); l = CDR(l)){ */
-/* x = CAR(l); */
-/* objprint(iostdout, x, 0); printf("\n"); */
-/* eval(x); */
-/* } */
dprintf("> err=%d\n", err);
return 0;
}
/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* Sxpr parsing definitions.
*/
-/** Size of a parser input buffer.
- * Tokens read must fit into this size (including trailing null).
+/** Initial size of a parser input buffer.
*/
-#define PARSER_BUF_SIZE 4096
+#define PARSER_BUF_SIZE 512
+
+/** Input buffer size increment (when it's full).
+ */
+#define PARSER_BUF_INCREMENT 512
struct Parser;
typedef int ParserStateFn(struct Parser *, char c);
char *name;
} ParserState;
-/** Structure representing an input source for the parser.
- * Can read from any IOStream implementation.
- */
typedef struct Parser {
+ /** Initial state function. */
+ ParserStateFn *begin;
+ /** Parse value. */
Sxpr val;
/** Error reporting stream (null for no reports). */
IOStream *error_out;
+ /** End-of-file flag, */
int eof;
/** Error flag. Non-zero if there has been a read error. */
int err;
int line_no;
/** Column number of input (reset on new line). */
int char_no;
- /** Lookahead character. */
- char c;
/** Buffer for reading tokens. */
- char buf[PARSER_BUF_SIZE];
- /** Size of token buffer. */
- int buf_n;
- int buf_i;
+ char *buf;
+ char *buf_end;
+ char *tok;
+ char *tok_end;
/** Line the last token started on. */
int tok_begin_line;
/** Character number the last token started on. */
* @param in parser
* @param flags flags mask
*/
-inline static void parser_flags_raise(Parser *in, int flags){
+inline static void Parser_flags_raise(Parser *in, int flags){
in->flags |= flags;
}
* @param in parser
* @param flags flags mask
*/
-inline static void parser_flags_lower(Parser *in, int flags){
+inline static void Parser_flags_lower(Parser *in, int flags){
in->flags &= ~flags;
}
*
* @param in parser
*/
-inline static void parser_flags_clear(Parser *in){
+inline static void Parser_flags_clear(Parser *in){
in->flags = 0;
}
extern int Parser_input(Parser *p, char *buf, int buf_n);
extern int Parser_input_eof(Parser *p);
extern int Parser_input_char(Parser *p, char c);
-extern void set_error_stream(Parser *z, IOStream *error_out);
-
-extern int parse_error_message(Parser *in, char *buf, int n);
-extern int has_error(Parser *in);
-extern int at_eof(Parser *in);
-
-int Parser_ready(Parser *p);
-Sxpr Parser_get_val(Parser *p);
-Sxpr Parser_get_all(Parser *p);
+extern void Parser_set_error_stream(Parser *z, IOStream *error_out);
+
+extern int Parser_error_message(Parser *in, char *buf, int n);
+extern int Parser_has_error(Parser *in);
+extern int Parser_at_eof(Parser *in);
+
+extern int Parser_ready(Parser *p);
+extern Sxpr Parser_get_val(Parser *p);
+extern Sxpr Parser_get_all(Parser *p);
+
+/* Internal parser api. */
+void Parser_pop(Parser *p);
+int Parser_push(Parser *p, ParserStateFn *fn, char *name);
+int Parser_return(Parser *p);
+int Parser_at_eof(Parser *p);
+int Parser_error(Parser *in);
+int Parser_set_value(Parser *p, Sxpr val);
+int Parser_intern(Parser *p);
+int Parser_string(Parser *p);
+int Parser_data(Parser *p);
+int Parser_uint(Parser *p);
+
+char *peek_token(Parser *p);
+char *copy_token(Parser *p);
+void new_token(Parser *p);
+int save_char(Parser *p, char c);
+int token_len(Parser *p);
#endif /* ! _XUTIL_SXPR_PARSER_H_ */
return s;
}
+/** Set the sign to use for converting a string to a number.
+ * Value is 1 for positive, -1 for negative.
+ *
+ * @param s input string
+ * @param sign where to put the sign
+ * @return rest of s to parse as a number
+ */
+inline static const char * convert_set_sign(const char *s, int *sign){
+ *sign = 1;
+ if(s){
+ if(*s == '+'){
+ *sign = 1;
+ s++;
+ } else if (*s == '-'){
+ *sign = -1;
+ s++;
+ }
+ }
+ return s;
+}
+
/** Get the numerical value of a digit in the given base.
*
* @param c digit character
return err;
}
+/** Convert a string to a long by parsing it as a number.
+ * Will accept hex or decimal in usual C syntax.
+ *
+ * @param str input string
+ * @param val where to put the result
+ * @return 0 if converted OK, negative otherwise
+ */
+int convert_atol(const char *str, long *val){
+ int err = 0;
+ unsigned long v = 0;
+ int base, sign = 1;
+ const char *s = str;
+
+ if(!s) {
+ err = -EINVAL;
+ goto exit;
+ }
+ s = convert_set_sign(s, &sign);
+ s = convert_set_base(s, &base);
+ for( ; !err && *s; s++){
+ int digit = convert_get_digit(*s, base);
+ if(digit<0){
+ err = -EINVAL;
+ goto exit;
+ }
+ v *= base;
+ v += digit;
+ }
+ if(sign < 0) v = -v;
+ exit:
+ *val = (err ? 0 : v);
+ return err;
+}
+
/** Combine a directory path with a relative path to produce
* a new path.
*
/*============================================================================*/
extern int convert_atoul(const char *s, unsigned long *v);
+extern int convert_atol(const char *s, long *v);
extern int path_concat(char *s, char *t, char **val);
#endif /* !_XUTIL_SYS_STRING_H_ */
if not pm: continue
xm = xendre.match(pm.group('cmd'))
if not xm: continue
- #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
pids.append(int(pm.group('pid')))
return pids
os.setuid(pwd.getpwnam(XEND_USER)[2])
return 0
except KeyError, error:
- print "Error: no such user '%s'" % XEND_USER
+ print >>sys.stderr, "Error: no such user '%s'" % XEND_USER
return 1
def stop(self):
self.listenChannels()
servers = SrvServer.create()
self.daemonize()
- print 'running serverthread...'
servers.start()
except Exception, ex:
print >>sys.stderr, 'Exception starting xend:', ex
def listenChannels(self):
def virqReceived(virq):
- print 'virqReceived>', virq
eserver.inject('xend.virq', virq)
self.channelF.setVirqHandler(virqReceived)
self.channelF.start()
def exit(self, rc=0):
- #reactor.disconnectAll()
if self.channelF:
self.channelF.stop()
# Calling sys.exit() raises a SystemExit exception, which only
from xen.web import reactor, protocol
-from xen.lowlevel import xu
-
from xen.xend import sxp
from xen.xend import PrettyPrint
-from xen.xend import EventServer
-eserver = EventServer.instance()
+from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendError import XendError
-
from xen.xend import XendRoot; xroot = XendRoot.instance()
-DEBUG = 1
+DEBUG = 0
class EventProtocol(protocol.Protocol):
"""Asynchronous handler for a connected event socket.
self.pretty = 0
# For debugging subscribe to everything and make output pretty.
- self.subscribe(['*'])
+ #self.subscribe(['*'])
self.pretty = 1
def dataReceived(self, data):
except SystemExit:
raise
except:
- if DEBUG:
- raise
- else:
- self.send_error()
+ self.send_error()
def loseConnection(self):
if self.transport:
return 0
def send_result(self, res):
- return self.send_reply(['ok', res])
+ if res is None:
+ resp = ['ok']
+ else:
+ resp = ['ok', res]
+ return self.send_reply(resp)
def send_error(self):
(extype, exval) = sys.exc_info()[:2]
def op_pretty(self, name, req):
self.pretty = 1
- return ['ok']
def op_console_disconnect(self, name, req):
id = sxp.child_value(req, 'id')
raise XendError('Missing console id')
id = int(id)
self.daemon.console_disconnect(id)
- return ['ok']
def op_info(self, name, req):
val = ['info']
# (sys.subscribe event*)
# Subscribe to the events:
self.subscribe(v[1:])
- return ['ok']
def op_sys_inject(self, name, v):
# (sys.inject event)
event = v[1]
eserver.inject(sxp.name(event), event)
- return ['ok']
def op_trace(self, name, v):
mode = (v[1] == 'on')
import controller
controller.DEBUG = (mode == 'on')
+ def op_domain_ls(self, name, v):
+ xd = xroot.get_component("xen.xend.XendDomain")
+ return xd.domain_ls()
+
+ def op_domain_configure(self, name, v):
+ domid = sxp.child_value(v, "dom")
+ config = sxp.child_value(v, "config")
+ if domid is None:
+ raise XendError("missing domain id")
+ if config is None:
+ raise XendError("missing domain config")
+ xd = xroot.get_component("xen.xend.XendDomain")
+ xd.domain_configure(domid, config)
+
+ def op_domain_unpause(self, name, v):
+ domid = sxp.child_value(v, "dom")
+ if domid is None:
+ raise XendError("missing domain id")
+ xd = xroot.get_component("xen.xend.XendDomain")
+ xd.domain_unpause(domid)
+
class EventFactory(protocol.ServerFactory):
"""Asynchronous handler for the event server socket.
"""
UTIL_LIB_SRC =
UTIL_LIB_SRC += allocate.c
UTIL_LIB_SRC += enum.c
+UTIL_LIB_SRC += fd_stream.c
UTIL_LIB_SRC += file_stream.c
UTIL_LIB_SRC += gzip_stream.c
UTIL_LIB_SRC += hash_table.c
UTIL_LIB_SRC += sys_net.c
UTIL_LIB_SRC += sys_string.c
#UTIL_LIB_SRC += util.c
-UTIL_LIB_SRC += xdr.c
+#UTIL_LIB_SRC += xdr.c
#----------------------------------------------------------------------------
# Xfrd.
XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o)
XFRD_PROG_OBJ += $(UTIL_LIB)
-# Flag controlling whether to use stubs.
-# Define to use stubs, undefine to use the real Xen functions.
-#CPPFLAGS += -D _XEN_XFR_STUB_
-
-ifeq ($(SXPR_DEBUG),1)
-CPPFLAGS += -D _XEN_XFR_STUB_ -D SXPR_PARSER_MAIN
-endif
-
CC := gcc
CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
CFLAGS += $(INCLUDES)
+
# Make gcc generate dependencies.
CFLAGS += -Wp,-MD,.$(@F).d
PROG_DEP = .*.d
# zlib library.
XFRD_LIBS += -lz
-CURL_FLAGS = $(shell curl-config --cflags)
-CURL_LIBS = $(shell curl-config --libs)
-CFLAGS += $(CURL_FLAGS)
-# libcurl libraries.
-XFRD_LIBS += $(CURL_LIBS)
-
#$(warning XFRD_LIBS = $(XFRD_LIBS))
all: build
dprintf(">\n");
if(!conn->parser){
conn->parser = Parser_new();
- set_error_stream(conn->parser, iostdout);
+ Parser_set_error_stream(conn->parser, iostdout);
}
while(!err && c >= 0 && !Parser_ready(conn->parser)){
c = IOStream_getc(conn->in);
*/
static void lzi_free(IOStream *s){
LZIState *state = lzi_state(s);
- IOStream_free(state->io);
LZIState_free(state);
s->data = NULL;
}
err = 0;
exit:
if(err){
- IOStream_free(io);
- IOStream_free(zio);
+ IOStream_close(io);
+ IOStream_close(zio);
zio = NULL;
}
return zio;
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
-#ifdef _XEN_XFR_STUB_
-typedef unsigned long u32;
-#else
#include "xc.h"
#include "xc_io.h"
-#endif
+
+#include "sxpr.h"
+#include "sxpr_parser.h"
+#include "file_stream.h"
+#include "fd_stream.h"
#include "xen_domain.h"
-#include "marshal.h"
-#include "xdr.h"
#include "xfrd.h"
#define MODULE_NAME "XFRD"
return xen_domain_configure(dom, vmconfig, vmconfig_n);
}
-#ifndef _XEN_XFR_STUB_
static int xc_handle = 0;
int xcinit(void){
xc_handle = 0;
}
}
-#endif
/** Write domain state.
*
char *vmconfig, int vmconfig_n,
int live, int resource){
int err = 0;
-#ifdef _XEN_XFR_STUB_
- char buf[1024];
- int n, k, d, buf_n;
- dprintf("> dom=%d\n", dom);
- err = marshal_uint32(io, dom);
- if(err) goto exit;
- err = marshal_string(io, vmconfig, vmconfig_n);
- if(err) goto exit;
- n = 32 * 1024 * 1024;
- n = 32 * 1024;
- buf_n = sizeof(buf);
- err = marshal_uint32(io, n);
- for(k = 0; k < n; k += d){
- d = n - k;
- if(d > buf_n) d = buf_n;
- err = marshal_bytes(io, buf, d);
- if(err) goto exit;
- dprintf("> k=%d n=%d\n", k, n);
- }
-
- dom = 99;
- err = domain_suspend(xend, dom);
- IOStream_close(io);
- exit:
-#else
XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
ioctxt->domain = dom;
ioctxt->io = io;
}
ioctxt->resource = resource;
err = xc_linux_save(xcinit(), ioctxt);
-#endif
dprintf("< err=%d\n", err);
return err;
}
char **vmconfig, int *vmconfig_n,
int *configured){
int err = 0;
-#ifdef _XEN_XFR_STUB_
- char buf[1024];
- int n, k, d, buf_n;
- dprintf(">\n");
- err = unmarshal_uint32(io, dom);
- if(err) goto exit;
- err = unmarshal_new_string(io, vmconfig, vmconfig_n);
- if(err) goto exit;
- err = unmarshal_uint32(io, &n);
- buf_n = sizeof(buf);
- for(k = 0; k < n; k += d){
- d = n - k;
- if(d > buf_n) d = buf_n;
- err = unmarshal_bytes(io, buf, d);
- if(err) goto exit;
- dprintf("> k=%d n=%d\n", k, n);
- }
- exit:
-#else
XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
dprintf(">\n");
ioctxt->io = io;
*vmconfig = ioctxt->vmconfig;
*vmconfig_n = ioctxt->vmconfig_n;
*configured = (ioctxt->flags & XCFLAGS_CONFIGURE);
-#endif
dprintf("< err=%d\n", err);
return err;
}
-#include <curl/curl.h>
-#include "http.h"
+typedef struct xend {
+ int fd;
+ IOStream *io;
+ Parser *parser;
+ int seeneof;
+} Xend;
-/** Flag indicating whether we need to initialize libcurl.
- */
-static int do_curl_global_init = 1;
+char *xend_server_addr(void){
+ char * val = getenv("XEND_EVENT_ADDR");
+ return (val ? val : "/var/lib/xend/event-socket");
+}
-/** Get a curl handle, initializing libcurl if needed.
- *
- * @return curl handle
+/** Open a unix-domain socket to the xend server.
*/
-static CURL *curlinit(void){
- if(do_curl_global_init){
- do_curl_global_init = 0;
- // Stop libcurl using the proxy. There's a curl option to
- // set the proxy - but no option to defeat it.
- unsetenv("http_proxy");
- curl_global_init(CURL_GLOBAL_ALL);
+int xend_open_fd(void){
+ struct sockaddr_un addr_un = { .sun_family = AF_UNIX };
+ struct sockaddr *addr = (struct sockaddr*)&addr_un;
+ int addr_n = sizeof(addr_un);
+ int err = 0;
+
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd < 0){
+ err = -errno;
+ perror("socket");
+ goto exit;
}
- return curl_easy_init();
+ strcpy(addr_un.sun_path, xend_server_addr());
+ if(connect(fd, addr, addr_n) < 0){
+ err = -errno;
+ perror("connect");
+ goto exit;
+ }
+ exit:
+ if(err && (fd >= 0)){
+ close(fd);
+ }
+
+ return (err ? err : fd);
}
-/** Curl debug function.
- */
-int curldebug(CURL *curl, curl_infotype ty, char *buf, int buf_n, void *data){
- // printf("%*s\n", buf_n, buf); /* Does not compile correctly on non 32bit platforms */
- fwrite(data, buf_n, 1, stdout);
- printf("\n");
- return 0;
+/** Close a connection to the server.
+ *
+ * @param xend connection
+*/
+void xend_close(Xend *xend){
+ if(!xend) return;
+ close(xend->fd);
+ Parser_free(xend->parser);
}
-/** Setup a curl handle with a url.
- * Creates the url by formatting 'fmt' and the remaining arguments.
+/** Open a connection to the server.
*
- * @param pcurl return parameter for the curl handle
- * @param url url buffer
- * @param url_n size of url
- * @param fmt url format string, followed by parameters
- * @return 0 on success, error code otherwise
+ * @param xend result parameter for the connection
+ * @return 0 on success, negative error code otherwise
*/
-static int curlsetup(CURL **pcurl, struct curl_slist **pheaders, char *url, int url_n, char *fmt, ...){
+int xend_open(Xend **xend){
int err = 0;
- va_list args;
- CURL *curl = NULL;
- struct curl_slist *headers = NULL;
- int n = 0;
+ Xend *val = ALLOCATE(Xend);
- curl = curlinit();
- if(!curl){
- eprintf("> Could not init libcurl\n");
- err = -ENOMEM;
- goto exit;
- }
- url_n -= 1;
- va_start(args, fmt);
- n = vsnprintf(url, url_n, fmt, args);
- va_end(args);
- if(n <= 0 || n >= url_n){
- err = -ENOMEM;
- eprintf("> Out of memory in url\n");
+ val->fd = xend_open_fd();
+
+ if(val->fd < 0){
+ err = val->fd;
goto exit;
}
- dprintf("> url=%s\n", url);
-#if DEBUG
- // Verbose.
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
- // Call the debug function on data received.
- curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curldebug);
-#else
- // No progress meter.
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
- // Completely quiet.
- curl_easy_setopt(curl, CURLOPT_MUTE, 1);
-#endif
- // Set the URL.
- curl_easy_setopt(curl, CURLOPT_URL, url);
-
- headers = curl_slist_append(headers, "Expect:");
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-
+ val->io = fd_stream_new(val->fd);
+ val->parser = Parser_new();
exit:
- if(err && curl){
- curl_easy_cleanup(curl);
- curl = NULL;
- }
- *pcurl = curl;
- if (pheaders)
- *pheaders = headers;
+ if(err) xend_close(val);
+ *xend = (err ? NULL : val);
return err;
}
-static void curlcleanup(CURL **pcurl, struct curl_slist **pheaders){
- if (*pcurl)
- curl_easy_cleanup(*pcurl);
- if (*pheaders)
- curl_slist_free_all(*pheaders);
- *pcurl = NULL;
- *pheaders = NULL;
+/** Read a response from a server connection.
+ */
+int xend_read_resp(Xend *xend, Sxpr *resp){
+ int err = 0;
+ Sxpr val = ONONE;
+ char buf[1024];
+ int buf_n = sizeof(buf), n;
+
+ for( ; ; ){
+ if(Parser_ready(xend->parser)){
+ val = Parser_get_val(xend->parser);
+ goto exit;
+ }
+ if(xend->seeneof){
+ err = -EIO;
+ goto exit;
+ }
+ memset(buf, 0, buf_n);
+ n = IOStream_read(xend->io, buf, 100);
+ if(n <= 0){
+ xend->seeneof = 1;
+ err = Parser_input_eof(xend->parser);
+ } else {
+ err = Parser_input(xend->parser, buf, n);
+ }
+ }
+ exit:
+ *resp = (err < 0 ? ONONE : val);
+ return err;
}
-/** Make the http request stored in the curl handle and get
- * the result code from the curl code and the http return code.
+
+/** Read a response from a server connection and decode the value.
*
- * @param curl curl handle
- * @return 0 for success, error code otherwise
+ * @param xend server connection
+ * @param resp result parameter for the response value
+ * @return 0 on success, negative error code otherwise
*/
-int curlresult(CURL *curl){
+int xend_read(Xend *xend, Sxpr *resp){
int err = 0;
- CURLcode curlcode = 0;
- long httpcode = 0;
+ Sxpr val = ONONE;
- curlcode = curl_easy_perform(curl);
- if(curlcode){
- eprintf("> curlcode=%d\n", curlcode);
- err = -EINVAL;
- goto exit;
- }
- curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &httpcode);
- if(httpcode != HTTP_OK){
- eprintf("> httpcode=%d\n", (int)httpcode);
- err = -EINVAL;
- goto exit;
+ dprintf(">\n");
+ for( ; ; ){
+ err = xend_read_resp(xend, &val);
+ if(err < 0) goto exit;
+
+ if(sxpr_is(sxpr_name(val), "event")){
+ // We don't care about events, try again.
+ err = 0;
+ continue;
+ } else if(sxpr_is(sxpr_name(val), "err")){
+ eprintf("> "); objprint(iostderr, val, 0); fprintf(stderr, "\n");
+ err = -EINVAL;
+ break;
+ } else {
+ err = 0;
+ val = sxpr_child0(val, ONULL);
+ break;
+ }
}
+#ifdef DEBUG
+ dprintf("> OK ");
+ objprint(iostdout, val, 0);
+ printf("\n");
+#endif
exit:
+ if(resp){
+ *resp = (err < 0 ? ONONE : val);
+ }
+ dprintf("> err=%d\n", err);
return err;
}
+/** Send a request to the server and return the result value in resp.
+ *
+ * @param xend server connection
+ * @param resp result parameter for the response value
+ * @param format request format followed by args to print
+ * @return 0 on success, negative error code otherwise
+ */
+int xend_call(Xend *xend, Sxpr *resp, char *format, ...){
+ va_list args;
+ int err;
+
+ dprintf("> ");
+ va_start(args, format);
+#ifdef DEBUG
+ vprintf(format, args); printf("\n");
+#endif
+ err = IOStream_vprint(xend->io, format, args);
+ va_end(args);
+ if(err < 0) goto exit;
+ IOStream_flush(xend->io);
+ err = xend_read(xend, resp);
+ exit:
+ dprintf("> err=%d\n", err);
+ return (err < 0 ? err : 0);
+}
+
/** Get xend to list domains.
* We use this to force xend to refresh its domain list.
*
*/
int xen_domain_ls(void){
int err = 0;
- CURL *curl = NULL;
- struct curl_slist *headers = NULL;
- char url[128] = {};
- int url_n = sizeof(url);
-
- dprintf(">\n");
- err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain", XEND_PORT);
+ Xend *xend = NULL;
+ err = xend_open(&xend);
if(err) goto exit;
- err = curlresult(curl);
+ err = xend_call(xend, NULL, "(domain.ls)");
exit:
- curlcleanup(&curl, &headers);
- dprintf("< err=%d\n", err);
+ xend_close(xend);
return err;
}
*/
int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
int err = 0;
- CURL *curl = NULL;
- struct curl_slist *headers = NULL;
- char url[128] = {};
- int url_n = sizeof(url);
- struct curl_httppost *form = NULL, *last = NULL;
- CURLFORMcode formcode = 0;
-
+ Xend *xend = NULL;
dprintf("> dom=%u\n", dom);
// List domains so that xend will update its domain list and notice the new domain.
xen_domain_ls();
-
- err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom);
+ // Now configure it.
+ err = xend_open(&xend);
if(err) goto exit;
-
- // Config field - set from vmconfig.
- formcode = curl_formadd(&form, &last,
- CURLFORM_COPYNAME, "config",
- CURLFORM_BUFFER, "config",
- CURLFORM_BUFFERPTR, vmconfig,
- CURLFORM_BUFFERLENGTH, vmconfig_n,
- CURLFORM_CONTENTTYPE, "application/octet-stream",
- CURLFORM_END);
- if(formcode){
- eprintf("> Error adding config field.\n");
- goto exit;
- }
- // Op field.
- formcode = curl_formadd(&form, &last,
- CURLFORM_COPYNAME, "op",
- CURLFORM_COPYCONTENTS, "configure",
- CURLFORM_END);
- if(formcode){
- eprintf("> Error adding op field.\n");
- err = -EINVAL;
- goto exit;
- }
- // POST the form.
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
- err = curlresult(curl);
+ err = xend_call(xend, NULL, "(domain.configure (dom %d) (config %*s))",
+ dom, vmconfig_n, vmconfig);
exit:
- curlcleanup(&curl, &headers);
- if(form) curl_formfree(form);
dprintf("< err=%d\n", err);
+ xend_close(xend);
return err;
}
*/
int xen_domain_unpause(uint32_t dom){
int err = 0;
- CURL *curl = NULL;
- struct curl_slist *headers = NULL;
- char url[128] = {};
- int url_n = sizeof(url);
- struct curl_httppost *form = NULL, *last = NULL;
- CURLFORMcode formcode = 0;
-
- dprintf("> dom=%u\n", dom);
-
- err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom);
+ Xend *xend = NULL;
+ err = xend_open(&xend);
if(err) goto exit;
-
- // Op field.
- formcode = curl_formadd(&form, &last,
- CURLFORM_COPYNAME, "op",
- CURLFORM_COPYCONTENTS, "unpause",
- CURLFORM_END);
- if(formcode){
- eprintf("> Error adding op field.\n");
- err = -EINVAL;
- goto exit;
- }
- // POST the form.
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
- err = curlresult(curl);
+ err = xend_call(xend, NULL, "(domain.unpause (dom %d))", dom);
exit:
- curlcleanup(&curl, &headers);
- if(form) curl_formfree(form);
- dprintf("< err=%d\n", err);
+ xend_close(xend);
return err;
}
XFR_MAX
};
-#ifndef SXPR_PARSER_MAIN
/** Short options. Options followed by ':' take an argument. */
static char *short_opts = (char[]){
OPT_PORT, ':',
/** Xfrd arguments. */
static Args *args = &_args;
-#endif
/** Initialize an array element for a constant to its string name. */
#define VALDEF(val) { val, #val }
exit:
if(io){
IOStream_close(io);
- IOStream_free(io);
}
if(err){
unlink(file);
int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){
int err = 0;
IOStream *io = NULL;
- int configured=0;
+ int configured = 0;
dprintf("> file=%s\n", file);
io = gzip_stream_fopen(file, "rb");
exit:
if(io){
IOStream_close(io);
- IOStream_free(io);
}
if(err){
xfr_error(xend, err);
return err;
}
-#ifndef SXPR_PARSER_MAIN
/** Parse command-line arguments and call the xfrd main program.
*
* @param arg argument count
}
return (err ? 1 : 0);
}
-#endif